import { JJUtil } from ".";
import JJLog from "./JJLog";

class JJTool {
    /**
     * 异步参数获取
     * @method asyncHronous
     * @for JJTool
     * @param {function} func 需要异步处理的函数
     * @param {Number} times 异步执行超时时间默认10000毫秒
     * @return {function} 返回整个方法
     */
    static asyncHronous = (func, times = 10000) => {
        if (Object.prototype.toString.call(func) === "[object Array]") {
            return Promise.race([
                ...func,
                new Promise(function (resolve, reject) {
                    //60秒超时
                    setTimeout(() => {
                        reject(new Error('请求超时，请稍后再试'));
                    }, times);
                })
            ]);
        } else {
            return Promise.race([
                func,
                new Promise(function (resolve, reject) {
                    //60秒超时
                    setTimeout(() => {
                        reject('请求超时，请稍后再试');
                    }, times);
                })
            ]);
        }
    }

    /**
     * 获取Url参数
     * @method urlParameter
     * @for JJTool
     * @param {String} name 参数说明:如果有参数则值返回当前name的参数与值，否则则全部返回
     * @return {Object} 返回值说明 标准的Object key:value 类型
     */
    static urlParameter = (name = '') => {
        let urlparam = window.location.search === '' ? window.location.hash : window.location.search;
        if (JJUtil.isEmpty(urlparam)) {
            return {}
        }
        const index = urlparam.indexOf('?')
        if (index < 0) {
            return {}
        }
        urlparam = urlparam.slice(index + 1);
        if (JJUtil.isEmpty(urlparam)) {
            return {};
        }
        const urlparamArray = urlparam.split("&");
        let param = {};
        if (JJUtil.isNotEmpty(urlparamArray)) {
            urlparamArray.forEach(item => {
                if (JJUtil.isNotEmpty(item) && item.indexOf('=') !== -1) {
                    let data = item.split('=');
                    if (name === data[0]) {
                        param = Object.assign({}, param, { [decodeURIComponent(data[0])]: decodeURIComponent(data[1]) })
                    } else if (name === '' || name === undefined) {
                        param = Object.assign({}, param, { [decodeURIComponent(data[0])]: decodeURIComponent(data[1]) })
                    }
                }
            })
        }
        return param;
    }

    /**
     * 通过Object key value形式生成url参数
     * @method urlFacturing
     * @for JJTool
     * @param {Object} obj 需要生成参数的Object
     * @param {boolean} host 是否有Url，默认true,选项:true、false,
     * @param {String} pathname host后面的url路径,当host 值为false，当前参数无效
     * @param {number} way pathname拼接方式,0为#,1为/，默认为0
     * @return {String} 返回生成后的参数字符串
     */

    static urlFacturing = (obj, host = true, pathname = '', way = 0) => {
        if (typeof obj != 'object' || !(obj instanceof Object)) {
            JJLog.error('请检查传入的obj参数是否是Object类型！')
            return null
        }

        let Facturing = host ? `${window.location.protocol}//${window.location.host}${window.location.pathname}` : '';
        if (0 === way) {
            Facturing += `#${pathname}`
        } else {
            Facturing += pathname
        }

        let body = ''
        for (let key in obj) {
            body += '&' + encodeURIComponent(key) + '=' + encodeURIComponent(obj[key])
        }

        if (JJUtil.isNotEmpty(body)) {
            if (Facturing.indexOf('?') !== -1) {
                Facturing += body
            } else {
                body = body.slice(1)
                Facturing += '?' + body
            }
        }

        return Facturing;
    }


    /**
     * 获取经纬度
     * @method getCoordinates
     * @for JJTool
     * @param {number} times 获取地理位置超时时间,10000,单位:ms(毫秒)
     * @param {object} errdata 获取经纬度失败或超时时默认经纬度,默认{longitude: 118.898872, latitude: 32.090948},南京市玄武区苏宁大道1号
     * @return {Object} 主要使用latitude:维度与longitude经度,gpsSuccess字段标示是否是真实定位还是失败后的虚拟定位，true：真实,false,虚拟
     */
    static getCoordinates = async (times = 10000, errdata = { longitude: 118.898872, latitude: 32.090948 }) => {
        const getError = Object.assign({}, {
            accuracy: 0,
            altitude: 0,
            altitudeAccuracy: 0,
            heading: 0,
            latitude: 0,
            longitude: 0,
            speed: null,
            gpsSuccess: false
        }, errdata)

        if (window.location.protocol !== 'https:') {
            return getError;
        }
        return this.asyncHronous(new Promise((resolve, reject) => {
            if (navigator.geolocation) {
                navigator.geolocation.getCurrentPosition(function (position) {
                    let { accuracy, altitude, altitudeAccuracy, heading, latitude, longitude, speed } = position.coords;
                    resolve(Object.assign({}, {
                        accuracy: accuracy,
                        altitude: altitude,
                        altitudeAccuracy: altitudeAccuracy,
                        heading: heading,
                        latitude: latitude,
                        longitude: longitude,
                        speed: speed,
                        gpsSuccess: true,
                    }))
                }, (err) => {
                    resolve(getError);
                })
            } else {
                JJLog.error('你的浏览器不支持当前地理位置信息获取');
                resolve(getError)
            }
        }), times).then(result => {
            return result;
        }).catch((err) => {
            return getError;
        })
    }
    /**
     * 根据经纬度获取行政单位
     * @method 方法名
     * @for JJTool
     * @param {function} callback 回调函数
     * 返回
     * address: "上海市浦东新区芳波路"
     * addressComponents:{city: "上海市",district: "浦东新区",province: "上海市",street: "芳波路",streetNumber: "",business: "张江,花木"}
     * point:{lng: 121.57783929999916, lat: 31.201984862816076}
     * surroundingPois: [],附近商家
     * gpsSuccess:bool,字段标示是否是真实定位还是失败后的虚拟定位，true：真实,false,虚拟
     * @param {function} errorcallback 失败回调
     * @param {number} times 超时时间，默认：6000毫秒
     * @param {object} errdata 获取经纬度失败或超时时默认经纬度,默认{longitude: 118.898872, latitude: 32.090948},南京市玄武区苏宁大道1号
     */
    static isgetCity = { baidu_BMap: false };
    static getCity = async (callback = () => { }, errorcallback = () => { }, times = 10000, errdata = { longitude: 118.898872, latitude: 32.090948 }) => {
        let boxDom = document.createElement('div');
        boxDom.id = 'l-map';
        document.body.appendChild(boxDom);
        /* global __DEV__ */
        let keys = __DEV__ === '' ? 'radcAbklUqyQqUa32GjehfHCsKM4UzwS' : 'PyMZbdSA36ReP4mAtEZtNHh12WomtnIC',
            url = `${window.location.protocol}//api.map.baidu.com/api?v=3.0&ak=${keys}&callback=BMapinitialize`;
        // url=`http://api.map.baidu.com/getscript?v=2.0&ak=${keys}&t=20190527152033`;
        let add = await this.addElements('script', { type: 'text/javascript', src: url });
        let { latitude = '', longitude = '', gpsSuccess = false } = await this.getCoordinates(5000, errdata); //使用H5获取经纬度
        window.BMapinitialize = () => {
            this.isgetCity.baidu_BMap = true;
        }
        this.asyncHronous([
            new Promise((resolve, reject) => Object.defineProperty(this.isgetCity, 'baidu_BMap', {
                set: async (value) => {
                    if (add && value) {
                        /* global BMap */
                        const maps = new BMap.Map("l-map");
                        let ggPoint = new BMap.Point(longitude, latitude);
                        maps.centerAndZoom(ggPoint, 15);// 创建地理编码实例
                        let myGeo = new BMap.Geocoder();
                        myGeo.getLocation(ggPoint, (result) => {
                            resolve(Object.assign({}, result, { gpsSuccess: gpsSuccess }));
                        });
                    } else {
                        reject('百度地图加载失败！');
                    }
                }
            })),
            new Promise((resolve, reject) => {
                /* global BMap */
                if (Object.prototype.toString.call(BMap) === '[object Object]' && Object.prototype.toString.call(BMap.Map) === '[object Function]') {
                    const maps = new BMap.Map("l-map");
                    let ggPoint = new BMap.Point(longitude, latitude);
                    maps.centerAndZoom(ggPoint, 15);// 创建地理编码实例
                    let myGeo = new BMap.Geocoder();
                    myGeo.getLocation(ggPoint, (result) => {
                        resolve(Object.assign({}, result, { gpsSuccess: gpsSuccess }));
                    });
                }

            })
        ], times).then(response => {
            callback(response);
        }).catch(e => {
            errorcallback(e);
            // throw  e;
        });
    }

    /**
    * 判断是否存在包含指定属性值的元素
    * @method isExistElement
    * @for JJTool
    * @param {String} labelName 标签名称
    * @param {Object} param 需要对比的标签属性集
    * @return {Boolean} true：存在； false：不存在
    */
    static isExistElement = (labelName = "", param = {}) => {
        if (JJUtil.isEmpty(labelName)) return false;
        const eleArr = Array.from(document.getElementsByTagName(labelName));
        if (JJUtil.isEmpty(eleArr)) {
            return false;
        } else {
            if (JJUtil.isEmpty(param)) return true;
            let result = eleArr.length > 0 && eleArr.filter(item => {
                if (JJUtil.isNotEmpty(param)) {
                    const keys = Object.keys(param);
                    const equleKeys = keys.filter(key => item[key].includes(param[key]));
                    return equleKeys.length === keys.length;
                } else {
                    return true;
                }
            }).length > 0;
            return result;
        }
    }
    /**
     * 异步动态添加标签加载成功或失败时返回或者标签已存在直接返回
     * @method addElements
     * @for JJTool
     * @param {string} labelName 标签名称
     * @param {object} param 标签参数
     * @return {boolean} 返回值说明
     */
    static addElements = async (labelName = "", param = {}) => {
        let Exist = this.isExistElement(labelName, param);
        if (!Exist) {
            return Promise.race([new Promise((resolve) => {
                let Elements = document.createElement(labelName);
                Object.keys(param).forEach(item => {
                    Elements[item] = param[item];
                })
                Elements.onload = () => {
                    resolve(true);
                }
                Elements.onerror = () => {
                    resolve(false);
                }
                document.body.appendChild(Elements);
            })]).then(result => {
                return result;
            });
        } else {
            return true;
        }
    }

    /**
     * @method getHost
     * @for JJTool
     * @return {String} 返回宿主名称 ,Wechat:微信中打开、Alipay：支付宝中打开、App:App中打开,H5:浏览器中打开
    **/
    static getHost = () => {
        const ua = window.navigator.userAgent.toLowerCase();
        if (ua.includes('micromessenger')) {
            return 'Wechat';
        } else if (ua.includes('alipayclient')) {
            return 'Alipay';
        } else if (ua.includes('JJWEBVIEW')) {
            return 'App';
        } else {
            return 'H5';
        };
    }

    /**
     *  动态设置URL参数
     *
     * @method getPagePathWithPageNameAndId
     * @for JJTool
     * @param {String} pageName 本地路由地址
     * @param {Object} param 本地路由地址中的必要参数
     * @return { String } 替换后的URL
     */
    static getPagePathWithPageNameAndId(pageName, param) {
        const allKeys = Object.keys(param);
        let pagePath = pageName;
        allKeys.forEach((key, index) => {
            let value = param[key];
            if (JJUtil.isNotNull(value)) {
                const type = Object.prototype.toString.call(value);
                if (type === "[object Array]" || type === "[object Object]") {
                    value = JSON.stringify(value);
                }
                pagePath = pagePath.replace(":" + key, String(value));
            }
        });
        return pagePath;
    }

    /**
     * 获取设备平台
     * @method isQqOrWeChat
     * @for JJTool
     * @returns {string} 返回浏览器名称
     */
    static isQqOrWeChat = () => {
        const userAgent = navigator.userAgent.toLowerCase();
        if (userAgent.match(/MicroMessenger\/[0-9]/i)) {
            return "微信";
        } else if (userAgent.match(/QQ\/[0-9]/i) && userAgent.match(/tbs\/[0-9]/i)) {
            return 'QQ';
        } else if (userAgent.match(/mqqbrowser\/[0-9]/i)) {
            return 'QQ浏览器';
        } else if (userAgent.match(/AlipayClient\//i)) {
            return '支付宝';
        } else if (userAgent.match(/Safari\/[0-9]/i) && userAgent.match(/chrome\/[0-9]/i) === null) {
            return 'Safari浏览器';
        } else if (userAgent.match(/Opera/)) {
            return 'Opera浏览器';
        } else if (userAgent.match(/BIDUBrowser/)) {
            return '百度浏览器';
        } else if (userAgent.match(/chrome\/[0-9]/i)) {
            return 'Chrome浏览器';
        } else if (userAgent.match(/Firefox/)) {
            return 'Firefox浏览器';
        } else if (userAgent.match(/UCWEB/) || userAgent.match(/UC/)) {
            return 'UC浏览器';
        } else if (userAgent.match(/UCWEB/)) {
            return '360浏览器';
        } else {
            return '浏览器';
        }
    }
    /**
     * 获取公网IP
     * @method getIp
     * @for JJTool
     * @return {String} 返回公网IP
     */
    static getIp = () => {
        return new Promise((resolve, reject) => {
            let setTime = setTimeout(() => {
                JJLog.error('IP获取失败')
                resolve({});
            }, 10000)
            let isExist = this.isExistElement('script', { src: 'https://pv.sohu.com/cityjson?ie=utf-8', type: 'text/javascript' });
            if (!isExist) {
                window.returnCitySN = {};
                this.addElement('script', { src: 'https://pv.sohu.com/cityjson?ie=utf-8', type: 'text/javascript' }, () => {
                    if (Object.keys(window.returnCitySN).length > 0) {
                        clearTimeout(setTime);
                        resolve(window.returnCitySN)
                    } else {
                        Object.defineProperty(window, window.returnCitySN, {
                            set(v) {
                                clearTimeout(setTime);
                                resolve(window.returnCitySN);
                            },
                        })
                    }
                }, () => {
                    clearTimeout(setTime);
                    JJLog.error('获取IP地址SKD获取失败！');
                    return {};
                });
            } else if (JJUtil.isNotEmpty(window.returnCitySN) && Object.keys(window.returnCitySN).length >= 2) {
                clearTimeout(setTime);
                resolve(window.returnCitySN || {});
            } else {
                clearTimeout(setTime);
                JJLog.error(window.returnCitySN | {})
                resolve(window.returnCitySN || {});
            }
        })
    }

    /**
     * @method addElement
     * @for JJTool
     * @param {string} labelName 标签名称
     * @param {object} param 标签参数
     * @param {function} loadok 成功回掉
     * @param {function} loaderr 失败回掉
     **/
    static addElement = (labelName = '', param = {}, loadok = () => { }, loaderr = () => { }) => {
        if (Object.prototype.toString.call(param) === '[object Object]' && labelName !== '') {
            let Element = document.createElement(labelName);
            let paramKeys = Object.keys(param);
            paramKeys.map(item => {
                Element[item] = param[item];
                return item;
            });
            Element.onerror = () => {
                if (this.getElementLength(labelName, param) <= 3) {
                    this.addElement(labelName, param);
                } else {
                    loaderr();
                }
            }
            Element.onload = () => loadok();
            document.body.appendChild(Element);
        }
    }

    /**
     * @method 获取标签添加次数
     * @param {string} labelName 标签名称
     * @param {object} param 标签参数
     * @return {number} 返回标签添加次数
     */
    static getElementLength = (labelName, param) => {
        if (JJUtil.isEmpty(labelName)) return 0;
        const eleArr = Array.from(document.getElementsByTagName(labelName));
        if (JJUtil.isEmpty(eleArr)) {
            return 0;
        } else if (eleArr.length > 0) {
            let result = eleArr.filter(item => {
                if (JJUtil.isNotEmpty(param)) {
                    const keys = Object.keys(param);
                    const equleKeys = keys.filter(key => item[key].includes(param[key]));
                    if (equleKeys.length === keys.length) {
                        return item;
                    } else {
                        return false;
                    }
                } else {
                    return item;
                }
            });
            return result.length;
        } else {
            return 0
        }
    }

    /**
     * 设置cookie
     * @param {string} name 
     * @param {string} value 
     * @param {number} expires  时间戳
     * @param {string} path 
     * @param {string} domain 
     * @param {boolean} secure 
     */
    static setCookie(name, value, expires = 0, path = null, domain = null, secure = false) {
        if (JJUtil.isEmpty(name) || JJUtil.isNull(value)) {
            return;
        }
        let cookieString = '';
        let expires_date = undefined;
        if (expires) {
            expires_date = new Date(expires);
        }
        cookieString = name + "=" + escape(value)
            + ((expires) ? ";expires=" + expires_date.toGMTString() : "")
            + ((path) ? ";path=" + path : "")
            + ((domain) ? ";domain=" + domain : "")
            + ((secure) ? ";secure" : "")
        document.cookie = cookieString
    }

    /**
     *  获取cookie里面数据
     * @type {c_name}
     */
    static getCookie(c_name) {
        var i, x, y, ARRcookies = document.cookie.split(";");
        for (i = 0; i < ARRcookies.length; i++) {
            x = ARRcookies[i].substr(0, ARRcookies[i].indexOf("="));
            y = ARRcookies[i].substr(ARRcookies[i].indexOf("=") + 1);
            x = x.replace(/^\s+|\s+$/g, "");
            c_name = c_name.replace(/^\s+|\s+$/g, "");
            if (x === c_name) {
                return unescape(y);
            }
        }
    }

    /**
     *  删除cookies
     * @type {c_name}
     */
    static clearCookie(name) {
        const exp = new Date();
        exp.setTime(exp.getTime() - 1);
        const cval = JJTool.getCookie(name);
        if (JJUtil.isNotEmpty(cval)) {
            document.cookie = name + "=" + cval + ";expires=" + exp.toGMTString();
        }
    }

    /**
     * 获取时间戳
     * @param {*} day 
     * @param {*} hour 
     * @param {*} minute 
     * @param {*} second 
     */
    static getTimestamp(day = 0, hour = 0, minute = 0, second = 0) {
        const minuteUnit = 60;
        const hourUnit = 60 * minuteUnit;
        const dayUnit = 24 * hourUnit;
        const expiresTime = new Date().getTime() + 1000 * (dayUnit * day + hourUnit * hour + minuteUnit * minute + second);
        return expiresTime
    }
}
export default JJTool;
